#!/usr/bin/env python
#
# Copyright 2012,2013 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#

from gnuradio import gr
from gnuradio import blocks
from gnuradio import filter
import pmt
from gnuradio.blocks import parse_file_metadata
import scipy
import sys
import os

try:
    import gnuradio.qtgui.plot_spectrogram_base as plot_base
except ImportError:
    import plot_spectrogram_base as plot_base

try:
    from gnuradio import qtgui
    from PyQt4 import QtGui, QtCore
    import sip
except ImportError:
    print "Error: Program requires PyQt4 and gr-qtgui."
    sys.exit(1)

class spectrogram_plot_c(plot_base.plot_base):
    def __init__(self, filelist, fc, samp_rate, psdsize, start,
                 nsamples, max_nsamples, avg=1.0):
        plot_base.plot_base.__init__(self, filelist, fc, samp_rate,
                                     psdsize, start, nsamples,
                                     max_nsamples, avg)
        self.read_samples = plot_base.read_samples_c
        self.dsize = gr.sizeof_gr_complex
        self.src_type = blocks.vector_source_c
        self.gui_snk = qtgui.waterfall_sink_c(self._psd_size,
                       filter.firdes.WIN_BLACKMAN_hARRIS,self._center_freq,
                       self._samp_rate,"Complex Float",
                       self._nsigs)
        self.setup()

class spectrogram_plot_f(plot_base.plot_base):
    def __init__(self, filelist, fc, samp_rate, psdsize, start,
                 nsamples, max_nsamples, avg=1.0):
        plot_base.plot_base.__init__(self, filelist, fc, samp_rate,
                                     psdsize, start, nsamples,
                                     max_nsamples, avg)
        self.read_samples = plot_base.read_samples_f
        self.dsize = gr.sizeof_float
        self.src_type = blocks.vector_source_f
        self.gui_snk = qtgui.waterfall_sink_f(self._psd_size,
                       filter.firdes.WIN_BLACKMAN_hARRIS,self._center_freq,
                       self._samp_rate,
                       "Float",
                       self._nsigs)
        self.setup()

class spectrogram_plot_b(plot_base.plot_base):
    def __init__(self, filelist, fc, samp_rate, psdsize, start,
                 nsamples, max_nsamples, avg=1.0):
        plot_base.plot_base.__init__(self, filelist, fc, samp_rate,
                                     psdsize, start, nsamples,
                                     max_nsamples, avg)
        self.read_samples = plot_base.read_samples_b
        self.dsize = gr.sizeof_float
        self.src_type = plot_base.source_chars_to_float
        self.gui_snk = qtgui.waterfall_sink_f(self._psd_size,
                       filter.firdes.WIN_BLACKMAN_hARRIS,self._center_freq,
                       self._samp_rate, "Bytes",
                       self._nsigs)
        self.setup()

class spectrogram_plot_i(plot_base.plot_base):
    def __init__(self, filelist, fc, samp_rate, psdsize, start,
                 nsamples, max_nsamples, avg=1.0):
        plot_base.plot_base.__init__(self, filelist, fc, samp_rate,
                                     psdsize, start, nsamples,
                                     max_nsamples, avg)
        self.read_samples = plot_base.read_samples_i
        self.dsize = gr.sizeof_float
        self.src_type = plot_base.source_ints_to_float
        self.gui_snk = qtgui.waterfall_sink_f(self._psd_size,
                       filter.firdes.WIN_BLACKMAN_hARRIS,
                       self._center_freq, self._samp_rate,
                       "Integers",
                       self._nsigs)
        self.setup()

class spectrogram_plot_s(plot_base.plot_base):
    def __init__(self, filelist, fc, samp_rate, psdsize, start,
                 nsamples, max_nsamples, avg=1.0):
        plot_base.plot_base.__init__(self, filelist, fc, samp_rate,
                                     psdsize, start, nsamples,
                                     max_nsamples, avg)
        self.read_samples = plot_base.read_samples_s
        self.dsize = gr.sizeof_float
        self.src_type = plot_base.source_shorts_to_float
        self.gui_snk = qtgui.waterfall_sink_f(self._psd_size,
                       filter.firdes.WIN_BLACKMAN_hARRIS,
                       self._center_freq, self._samp_rate,
                       "Shorts",
                       self._nsigs)
        self.setup()

def read_header(filelist):
   filename = filelist[0] + '.hdr'
   try:
      handle = open(filename,"rb")
   except IOError:
      return
   hdr_start = handle.tell()
   header_str = handle.read(parse_file_metadata.HEADER_LENGTH)
   if( len(header_str) == 0 ):
      return
   # String to PMT Conversion
   try:
      header = pmt.deserialize_str(header_str)
   except RuntimeError:
      sys.stderr.write("Can't deserialize header: invalid/corrupt data\n")
      sys.exit(1)
   info = parse_file_metadata.parse_header(header,False)
   return info

def main():
   description = 'Plots the spectrogram (waterfall) of a file with detached header.'
   description += ' Assumes header is <input_filename>.hdr'
   (options, args) = plot_base.setup_options(description)
   filelist = list(args)
   # Attempt to read the header information
   info = read_header(filelist)
   # If no header, quit
   if not info:
      sys.stderr.write('Header not found\n')
      sys.exit(1)

   max_nsamples = plot_base.find_max_nsamples(filelist)
   srate = info["rx_rate"]

   # Dispatch the proper function
   # Complex Types
   if(info["cplx"] == True):
      if( info["type"] == "float" ):
         tb = spectrogram_plot_c(filelist,
                            options.center_frequency,srate,
                            options.psd_size,
                            options.start, options.nsamples, max_nsamples,
                            options.average);
      else:
         sys.stderr.write("Complex File Type " + info["type"]+ " not supported.\n")
   # Real Types
   else:
      if( info["type"] == "bytes" ):
         tb = spectrogram_plot_b(filelist,
                            options.center_frequency,srate,
                            options.psd_size,
                            options.start, options.nsamples, max_nsamples,
                            options.average);
      elif( info["type"] == "int" ):
         tb = spectrogram_plot_i(filelist,
                            options.center_frequency,srate,
                            options.psd_size,
                            options.start, options.nsamples, max_nsamples,
                            options.average);
      elif( info["type"] == "float" ):
         tb = spectrogram_plot_f(filelist,
                            options.center_frequency,srate,
                            options.psd_size,
                            options.start, options.nsamples, max_nsamples,
                            options.average);
      elif( info["type"] == "short" ):
         tb = spectrogram_plot_s(filelist,
                            options.center_frequency,srate,
                            options.psd_size,
                            options.start, options.nsamples, max_nsamples,
                            options.average);
      else:
        sys.stderr.write("Real File Type " + info["type"] + " not supported\n")
   main_box = plot_base.plot_spectrogram_form(tb, 'GNU Radio Spectrogram Plot')
   main_box.show()

   tb.run()
   tb.qapp.exec_()

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass
